七牛云这家公司挺有意思,通过笔试后还有open question
环节,简单地说就是做一个在线相册的小项目。其中多文件上传我以前没做过,看似简单的问题竟然也折腾了我一个晚上。
我前端用的是vue-cli
,后端用的是koa2
。首先我查看了koa2
官方在github
上的单文件上传示例和多文件上传示例。
单文件上传示例很简单,但前端的网页用的是原生表单的提交方式,可我的项目得用ajax
。多文件上传示例的app.js
比较易懂。于是现在的问题是前端要怎么写。
这里有两篇文章:Vue+axios提交表单数据(含单文件上传)和如何使用formData上传file数组。这两篇文章把vue
和多文件上传两个难点都给覆盖了。
以下是前端表单的部分代码。为了简洁去除了样式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <form enctype="multipart/form-data"> <input type="file" v-on:change="getFile($event)" multiple> <button v-on:click="submitForm()" type="button"> 上传文件 </button> </form> ............ methods: { getFile(event) { //this.files不是数组 this.files = event.target.files; }, submitForm() { let formData = new FormData(); //基本数据类型可以直接append formData.append('userId', this.$store.state.userInfo.id); //但formData里不能直接append数组 for (let item of this.files) { //得循环append元素 formData.append('fileArr', item); } let instance = this.$axios.create({ .............. headers: { //使用了koa-jwt验证 'Authorization': 'Bearer ' + this.$store.state.token, //据说XHR对象能自动识别form-data?待验证 'Content-Type': 'multipart/form-data' } }); instance.post('/api/uploadPhoto', formData) .then(function (response) { console.log(response.data.newPhotos); }) .catch(function (error) { alert("上传失败!"); console.log(error); }); } }
|
其中this.files
的结构如下文所示。
FileList {0: File(357224), 1: File(250584), 2: File(245061), length: 3}
注意!FileList
不是Array
!这点让我懵逼了好一阵子,下意识地用数组处理却老是报错……不过可以用for...of
循环遍历。
其中的每项元素如下文所示。
File(357224) {
name: "安贞堡.jpg",
lastModified:1486307059006,
lastModifiedDate: Sun Feb 05 2017 23:04:19 GMT+0800 (中国标准时间),
webkitRelativePath: "",
size: 357224,
.......
}
后端接收到数据后处理方法如下文所示。和前面几篇文章有些区别,毕竟我还要把图片信息存入数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const files = ctx.request.body.files.fileArr; for (let value of files) { let reader = fs.createReadStream(value.path); let stream = fs.createWriteStream(path.join("download", Math.random().toString() + value.name)); reader.pipe(stream); console.log('uploading %s -> %s', value.name, stream.path); let photo = await Photo.create({ userId: ctx.request.body.fields.userId, path: stream.path.replace('download\\', ''), like: 0 }); newPhotos.push(photo); } ctx.rest({ newPhotos });
|
New-Show 项目到目前依然没有完成。以后还会有多篇和它相关的博文。下一篇讲的是后端的大致结构,包括模型、ORM框架、配置文件、自动化的一些东西,敬请期待。